
pipeline {
    agent { label "label-master" }

    options {
        timestamps()                    // 在日志中打印时间
        timeout(time:1, unit:'HOURS')   // 流水线超时设置为1H
        // retry(2)                        // 失败重试2次
    }
    
    //最好在配置里创建一遍或者点一次build now，否则第一次运行没有Build with parameters
    parameters {
        // choice (name: 'EnvType', choices: ['dev20', 'dev20-QA'], description: '发布的环境')
        extendedChoice ( 
            name: 'EnvType', 
            defaultValue: 'dev20', 
            description: '发布环境, dev20: 20服务器的8012端口，用于develop； dev20-CommonRelease: 20服务器的8013端口，用于release/CommonRelease', 
            multiSelectDelimiter: ';', 
            quoteValue: false, 
            saveJSONParameterToFile: false, 
            type: 'PT_RADIO', 
            value:'dev20,dev20-CommonRelease', 
            visibleItemCount: 3
        )
        extendedChoice ( 
            name: 'ProjectNames', 
            defaultValue: '', 
            description: '发布的项目，可多选。注意：配置相关的文件需要自己手动修改', 
            multiSelectDelimiter: ';', 
            quoteValue: false, 
            saveJSONParameterToFile: false, 
            type: 'PT_MULTI_SELECT', 
            value:'trunklpg,SaaSAPPlpg,DccAdmin,NewWXShoplpg,09API_WebAPI,09API_WebAPI_LPG', 
            visibleItemCount: 7
        )
        gitParameter (
            name: 'Branch', 
            type: 'PT_BRANCH',
            defaultValue: 'develop', 
            //branchFilter: 'origin/(develop|release/CommonRelease)',
            branchFilter: 'origin/(.*)',
            sortMode: 'ASCENDING_SMART'
        )
    }

    stages {
        stage("InitParamters") {
            steps {
                script {
                    wrap([$class: 'BuildUser']) {
                        buildName "${BUILD_NUMBER}-${env.BUILD_USER}-${EnvType}-${Branch}-${ProjectNames}"
                    }
                    if (ProjectNames == "") {
                        println "The ProjectNames does not exists."
                        error "This pipeline stops here!"
                    }

                    json_file = "C:\\Jenkins\\resources\\input.lanyang.json"
                    Boolean isExists = fileExists json_file
                    if (!isExists) {
                        println "The Input_Json File does not exists."
                        error "This pipeline stops here!"
                    }
                    prop = readJSON file : json_file
                    slnFolder = prop.projects.slnFolder ? prop.projects.slnFolder : ""
                    println "slnFolder: " + slnFolder
                    publishFolder = prop.projects.publishFolder ? prop.projects.publishFolder : ""
                    println "publishFolder: " + publishFolder
                    publishProfileFolder = prop.projects.publishProfileFolder ? prop.projects.publishProfileFolder : ""
                    println "publishProfileFolder: " + publishProfileFolder
                    isCrossServer = false
                    println "isCrossServer: " + isCrossServer
                    sharedFolder = prop.envs[EnvType].sharedFolder ? prop.envs[EnvType].sharedFolder : ""
                    println "sharedFolder: " + sharedFolder
                    packageFolder = prop.envs[EnvType].packageFolder ? prop.envs[EnvType].packageFolder : ""
                    println "packageFolder: " + packageFolder
                    
                    msbuild = prop.projects.msbuild ? prop.projects.msbuild : ""
                    println "msbuild: " + msbuild
                    zipPath = prop.projects.zipPath ? prop.projects.zipPath : ""
                    println "zipPath: " + zipPath
                    excludeFolderPath = prop.projects.excludeFolderPath ? prop.projects.excludeFolderPath : ""
                    println "excludeFolderPath: " + excludeFolderPath
                    excludeFilePath = prop.projects.excludeFilePath ? prop.projects.excludeFilePath : ""
                    println "excludeFilePath: " + excludeFilePath
                    excludeFolderPathBackup = prop.projects.excludeFolderPathBackup ? prop.projects.excludeFolderPathBackup : ""
                    println "excludeFolderPathBackup: " + excludeFolderPathBackup
                    excludeFilePathBackup = prop.projects.excludeFilePathBackup ? prop.projects.excludeFilePathBackup : ""
                    println "excludeFilePathBackup: " + excludeFilePathBackup

                    isRestorePackage = prop.features.restorePackage ? prop.features.restorePackage : false
                    println "isRestorePackage: " + isRestorePackage
                    isBuildSolution = prop.features.buildSolution ? prop.features.buildSolution : false
                    println "isBuildSolution: " + isBuildSolution
                    isPublishProject = prop.features.publishProject ? prop.features.publishProject : false
                    println "isPublishProject: " + isPublishProject
                    isZipPackage = prop.features.zipPackage ? prop.features.zipPackage : false
                    println "isZipPackage: " + isZipPackage
                    isCopyPackage = prop.features.copyPackage ? prop.features.copyPackage : false
                    println "isCopyPackage: " + isCopyPackage
                    isBackup = prop.features.backup ? prop.features.backup : false
                    println "isBackup: " + isBackup
                    isDeploy = prop.features.deploy ? prop.features.deploy : false
                    println "isDeploy: " + isDeploy
                    isWarmup = prop.features.warmup ? prop.features.warmup : false
                    println "isWarmup: " + isWarmup
                    
                }
            }
        }
        
        stage('Checkout') { 
            steps {
                dir("D:\\GasErpwyy2021") {
                    script {
                        println "Checkout" 
                        checkout scmGit(
                            branches: [[name: 'refs/heads/' + Branch]],
                            extensions: [], 
                            userRemoteConfigs: [[
                                credentialsId: 'lufei.git', 
                                url: 'http://119.136.30.117:8808/r/GasErpwyy2021.git'
                            ]]
                        )
                    }
                }
            }
        }

        stage('Build') { 
            agent {  
                node { 
                    label 'label-master' 
                    customWorkspace 'D:\\GasErpwyy2021'
                }
            } 
            stages {
                stage('Restore packages') { 
                    when {
                        beforeAgent true
                        expression {
                            return isRestorePackage == true
                        }
                    }
                    steps {
                        timeout(time:5, unit:'MINUTES') {
                            script {
                                println "restore packages" 
                                bat """
                                    echo "[Debug:info] start restore packages for GasErpwyy2021
                                    C:\\Jenkins\\nuget\\nuget.exe restore ${slnFolder}\\GasErpwyy2021.sln
                                    IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                    :OK
                                    ECHO command success
                                    EXIT 0

                                    :ERROR
                                    ECHO command failed
                                    EXIT 1
                                """
                            }
                        }
                    }
                }
                stage('Build solution') { 
                    when {
                        beforeAgent true
                        expression {
                            return isBuildSolution == true
                        }
                    }
                    steps {
                        timeout(time:30, unit:'MINUTES') {
                            script {
                                println "build solution" 
                                bat """
                                    echo "[Debug:info] start build project - AttachPackage
                                    "${msbuild}" "${slnFolder}\\01.Common\\AttachPackage\\AttachPackage.csproj" -t:build /p:WarningLevel=0
                                    IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                    echo "[Debug:info] start build solution GasErpwyy2021
                                    "${msbuild}" "${slnFolder}\\GasErpwyy2021.sln" -t:build /p:WarningLevel=0
                                    IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                    :OK
                                    ECHO command success
                                    EXIT 0

                                    :ERROR
                                    ECHO command failed
                                    EXIT 1
                                """
                            }
                        }
                    }
                }
                stage('Publish project') { 
                    when {
                        beforeAgent true
                        expression {
                            return isPublishProject == true
                        }
                    }
                    steps {
                        timeout(time:20, unit:'MINUTES') {
                            script {
                                // for (project_name in ProjectNames.tokenize(';')) {
                                for (project_name in ProjectNames.split(';')) {
                                    println "start publish project: "  + project_name

                                    publishproj = prop.projects[project_name].publishproj ? prop.projects[project_name].publishproj : ""
                                    println "publishproj: " + publishproj                                    
                                    publishProfile = prop.projects[project_name].publishProfile ? prop.projects[project_name].publishProfile : ""
                                    println "publishProfile: " + publishProfile
                                    
                                    bat """
                                        "${msbuild}" "${slnFolder}\\${publishproj}" /p:DeployOnBuild=true /p:PublishProfile="${publishProfileFolder}\\${publishProfile}" /p:WarningLevel=0
                                        IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                        :OK
                                        ECHO command success
                                        EXIT 0
                                        
                                        :ERROR
                                        ECHO command failed
                                        EXIT 1
                                    """

                                    if (project_name == "trunklpg") {
                                        bat """
                                            set projectName=${project_name}
                                            set publishFolder="${publishFolder}"
                                            
                                            cd /d %publishFolder%
                                            cd %projectName%
                                            cd SaasHTML5
                                            
                                            call JS_uglify_minify.bat
                                            ::IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                            ping /n  20  127.0.0.1 > nul  
                                            :: 这个主要任务是通过ping ip 的任务起到延时 作用  /n 后的20 是 持续20s;时间可以自行修改

                                            :OK
                                            ECHO command success
                                            EXIT 0
                                            
                                            :ERROR
                                            ECHO command failed
                                            EXIT 1
                                        """
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        stage('Test') { 
            steps {
                println "Test" 
            }
        }
        stage('PrePackage') { 
            stages {
                stage('ZipPackage') { 
                    when {
                        beforeAgent true
                        expression {
                            return isZipPackage == true
                        }
                    }
                    steps {
                        timeout(time:30, unit:'MINUTES') {
                            script {
                                for (project_name in ProjectNames.tokenize(';')) {
                                    println "start zip package: " + project_name  
                                    bat """
                                        set env=${EnvType}
                                        set projectName=${project_name}
                                        set publishFolder="${publishFolder}"
                                        set today=%date:~0,4%%date:~5,2%%date:~8,2%
                                        set zip="${zipPath}"

                                        echo "[Debug:info] env=%env%"
                                        echo "[Debug:info] projectName=%projectName%"

                                        cd /d %publishFolder%
                                        set fileName=%projectName%_%today%.7z
                                        set zipFilePath=.\\zipPackages\\%fileName%

                                        If exist %zipFilePath% (
                                            echo "[Debug:info] start delete previous zip package: %zipFilePath%"
                                            del /q %zipFilePath%
                                        )
                                        IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                        echo "[Debug:info] start delete zip packages that more then 3 days"
                                        forfiles /p ".\\zipPackages" /s /m *.* /d -3 /c "cmd /c del @path"

                                        echo "[Debug:info] start zip package for %projectName%"
                                        %zip% a %zipFilePath% .\\%projectName%\\* -xr@"${excludeFolderPath}" -x@"${excludeFilePath}"
                                        IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                        :OK
                                        ECHO command success
                                        EXIT 0

                                        :ERROR
                                        ECHO command failed
                                        EXIT 1
                                    """
                                }
                            }
                        }
                    }
                }
                stage('CopyPackage') {
                    when {
                        beforeAgent true
                        expression {
                            return isCopyPackage == true
                        }
                    }
                    steps {
                        withCredentials([usernamePassword(credentialsId: 'lufei.ssh', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
                            timeout(time:30, unit:'MINUTES') {
                                script {
                                    for (project_name in ProjectNames.tokenize(';')) {
                                        println "start copy package:" + project_name
                                        bat """
                                            set projectName=${project_name}
                                            set sharedFolder="${sharedFolder}"
                                            set today=%date:~0,4%%date:~5,2%%date:~8,2%
                                            set fileName=%projectName%_%today%.7z
                                            set zipFilePath=.\\zipPackages\\%fileName%
                                            
                                            cd /d "${publishFolder}"

                                            :: 主节点时不用copy包, 设置sharedFolder=""
                                            IF %sharedFolder% == "" (
                                                echo "[Debug:info] sharedFolder is empty"
                                                GOTO OK
                                            )
                                            
                                            echo "[Debug:info] start connect sharedFolder: %sharedFolder%"
                                            net use %sharedFolder% ${PASSWORD} /user:"${USERNAME}"
                                            IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                            If exist %sharedFolder%\\%fileName% (
                                                echo "[Debug:info] start delete previous package"
                                                del /q %sharedFolder%\\%fileName%
                                            )
                                            IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                            echo "[Debug:info] start copy package to deploy package folder: %sharedFolder%"
                                            xcopy /c /y /i %zipFilePath% "%sharedFolder%\\"
                                            IF %ERRORLEVEL% NEQ 0 GOTO ERROR

                                            :OK
                                            ECHO command success
                                            EXIT 0

                                            :ERROR
                                            ECHO command failed
                                            EXIT 1
                                        """
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        stage('Deploy') {
            agent { label "label-${EnvType}" }
            
            steps {
                // startup backup sites
                timeout(time:15, unit:'MINUTES') {
                    script {
                        if (isDeploy == true) {
                            println "start startup backup sites"
                            for (site in prop.envs[EnvType].backupSites) {
                                siteName = site.siteName ? site.siteName : ""
                                appPoolName = site.appPoolName ? site.appPoolName : ""
                                operateIIS("start", siteName, appPoolName, isCrossServer)
                            }
                        }
                    }
                }

                // deploy projects
                timeout(time:30, unit:'MINUTES') {
                    script {
                        for (project_name in ProjectNames.tokenize(';')) {
                            println "start deploy project: " + project_name
                            index = 0
                            for (site in prop.envs[EnvType][project_name]) {
                                siteName = site.siteName ? site.siteName : ""
                                webPath = site.webPath ? site.webPath : ""
                                appPoolName = site.appPoolName ? site.appPoolName : ""
                                healthUrl = site.healthUrl ? site.healthUrl : ""

                                println "webPath: " + webPath
                                println "healthUrl: " + healthUrl
                                                            
                                if (isBackup == true && index == 0) {
                                    println "start backup running project"
                                    backupPackages(project_name, webPath, zipPath, env.BUILD_NUMBER, excludeFolderPathBackup, excludeFilePathBackup)                                    
                                } else {
                                    println "skip backup running project"
                                }
                                index++

                                if (isDeploy == true) {
                                    println "start unzip project deploy package"
                                    if (sharedFolder == "") {
                                        packageFolder = publishFolder + "\\zipPackages"
                                    }
                                    println "packageFolder: " + packageFolder

                                    operateIIS("stop", siteName, appPoolName, isCrossServer)
                                    unzipPackage(project_name, packageFolder, webPath, zipPath)                                 
                                    operateIIS("start", siteName, appPoolName, isCrossServer)
                                } else {
                                    println "skip unzip project deploy package"
                                }

                                println "start warmup project: " + project_name
                                retry(5) {                                    
                                    def response = httpRequest "${healthUrl}"
                                    if (response.status != 200) {
                                        error "The warmup failed!"
                                    }
                                }
                            }
                        }
                    }
                }
                
                // stop backup sites
                timeout(time:15, unit:'MINUTES') {
                    script {
                        if (isDeploy == true) {
                            println "start stop backup sites"
                            for (site in prop.envs[EnvType].backupSites) {
                                siteName = site.siteName ? site.siteName : ""
                                appPoolName = site.appPoolName ? site.appPoolName : ""
                                operateIIS("stop", siteName, appPoolName, isCrossServer)
                            }
                        }
                    }
                }
            }                
        }
    }

    post {
        success {
            wrap([$class: 'BuildUser']) {
                echo '恭喜您，构建成功！！！'
                mail subject: "CI报告: ${env.JOB_NAME} [${env.BUILD_NUMBER}] 执行成功",
                body: """
                    <style>
                    ul li { padding: 8px 0; }
                    ul li .title { min-width: 130px; display: inline-block; }
                    </style>
                    <div id="content">
                        <div id="sum2">
                            <h2><font color=#00CD00>Jenkins 运行成功</font></h2>
                            <ul>
                                <li><label class="title">Jenkins Job Name:</label> <a href="${env.BUILD_URL}">${env.JOB_NAME} [${env.BUILD_NUMBER}]</a></li>
                                <li><label class="title">Jenkins Job URL:</label> <a href='${env.BUILD_URL}'>${env.BUILD_URL}</a></li>
                                <li><label class="title">Jenkins Log:</label> <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                                <li><label class="title">发布环境:</label> ${params.EnvType}</li>
                                <li><label class="title">发布分支:</label> ${params.Branch}</li>
                                <li><label class="title">发布项目:</label> <font color=#00CD00>${params.ProjectNames}</font></li>
                                <li><label class="title">发布人:</label> ${BUILD_USER}</li>
                            </ul>
                        </div>
                    </div>
                    """,
                charset: 'utf-8',
                from: '2167162@qq.com',
                mimeType: 'text/html',
                to: "${env.BUILD_USER_EMAIL}, lufei@lanyang.com"
            }
        }
        failure {
            wrap([$class: 'BuildUser']) {
                echo '抱歉，构建失败！！！'
                mail subject: "CI报告: ${env.JOB_NAME} [${env.BUILD_NUMBER}] 执行失败",
                body: """
                    <style>
                    ul li { padding: 8px 0; }
                    ul li .title { min-width: 130px; display: inline-block; }
                    </style>
                    <div id="content">
                        <div id="sum2">
                            <h2><font color=#EE0000>Jenkins 运行失败</font></h2>
                            <ul>
                                <li><label class="title">Jenkins Job Name:</label> <a href="${env.BUILD_URL}">${env.JOB_NAME} [${env.BUILD_NUMBER}]</a></li>
                                <li><label class="title">Jenkins Job URL:</label> <a href='${env.BUILD_URL}'>${env.BUILD_URL}</a></li>
                                <li><label class="title">Jenkins Log:</label> <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
                                <li><label class="title">发布环境:</label> ${params.EnvType}</li>
                                <li><label class="title">发布分支:</label> ${params.Branch}</li>
                                <li><label class="title">发布项目:</label> <font color=#EE0000>${params.ProjectNames}</font></li>
                                <li><label class="title">发布人:</label> ${BUILD_USER}</li>
                            </ul>
                        </div>
                    </div>
                """,
                charset: 'utf-8',
                from: '2167162@qq.com',
                mimeType: 'text/html',
                to: "${env.BUILD_USER_EMAIL}, lufei@lanyang.com"
            }
        }
    }
}

def operateIIS(operate, siteName, appPoolName, isCrossServer) {
    println "start startIIS function"
    println "siteName:" + siteName
    println "appPoolName:" + appPoolName

    retry(2) {
        bat """
            ::%1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c %~s0 ::","","runas",1)(window.close)&&exit

            set siteName="${siteName}"
            set appPoolName="${appPoolName}"
            
            IF %siteName% NEQ "" (
                echo "[Debug:info] ${operate} site: %siteName%"
                C:\\Windows\\System32\\inetsrv\\appcmd.exe ${operate} site /site.name:%siteName%
                IF %ERRORLEVEL% NEQ 0 GOTO ERROR
            )

            IF %appPoolName% NEQ "" (
                echo "[Debug:info] ${operate} app pool: %appPoolName%"
                C:\\Windows\\System32\\inetsrv\\appcmd.exe ${operate} apppool /apppool.name:%appPoolName%
                IF %ERRORLEVEL% NEQ 0 GOTO ERROR
            )
            
            :OK
            ECHO command success
            EXIT 0

            :ERROR
            ECHO command failed
            EXIT 1
        """
        sleep(30)
    }
}

def backupPackages(project_name, webPath, zipPath, build_number, excludeFolderPathBackup, excludeFilePathBackup) {
    println "start backupPackages function"
    bat """
        set projectName=${project_name}
        set webPath=${webPath}
        set zip="${zipPath}"
        set today=%date:~0,4%%date:~5,2%%date:~8,2%

        echo "[Debug:info] projectName=%projectName%"
        echo "[Debug:info] webPath=%webPath%"

        IF "%webPath%" == "" (
            echo "[Error:info] not exists web path: %webPath%"
            GOTO ERROR
        )

        cd /d %webPath%
        cd ..\\
        set fileName=%projectName%_%today%_${build_number}.7z
        set zipFilePath=.\\backupPackages\\%fileName%

        echo "[Debug:info] start delete backup packages that more then 3 days"
        forfiles /p ".\\backupPackages" /s /m *.* /d -3 /c "cmd /c del @path"
        
        echo "[Debug:info] start zip %projectName% site to backup"
        %zip% a %zipFilePath% %webPath% -xr@"${excludeFolderPathBackup}" -x@"${excludeFilePathBackup}"
        IF %ERRORLEVEL% NEQ 0 GOTO ERROR

        :OK
        ECHO command success
        EXIT 0

        :ERROR
        ECHO command failed
        EXIT 1
    """
}

def unzipPackage(project_name, packageFolder, webPath, zipPath) {
    println "start unzipPackage function"
    retry(2) {
        bat """
            set today=%date:~0,4%%date:~5,2%%date:~8,2%
            set projectName=${project_name}
            set packageFolder=${packageFolder}
            set webPath=${webPath}
            set packagePath="%packageFolder%\\%projectName%_%today%.7z"
            set zip="${zipPath}"

            echo "[Debug:info] projectName=%projectName%"
            echo "[Debug:info] packagePath=%packagePath%"
            echo "[Debug:info] webPath=%webPath%"

            echo "[Debug:info] start delete zip packages that more then 3 days"
            forfiles /p "%packageFolder%" /s /m *.* /d -3 /c "cmd /c del @path"

            IF "%webPath%" == "" (
                echo "[Error:info] not exists web path: %webPath%"
                GOTO ERROR
            )
                                                        
            If exist %webPath%\\bin (
                echo "[Debug:info] start delete bin folder: %webPath%\\bin"
                rd /s /q %webPath%\\bin
            )
            
            echo "[Debug:info] start unzip package to project folder: %webPath%"
            %zip% x %packagePath% -o%webPath% -aoa
            IF %ERRORLEVEL% NEQ 0 GOTO ERROR

            :OK
            ECHO command success
            EXIT 0

            :ERROR
            ECHO command failed
            EXIT 1
        """
    }
}